import time
from common import logger
from fastapi import Request
from fastapi.routing import APIRoute
from typing import Callable
from fastapi.responses import Response
from common import json_helper
from datetime import datetime
from user_agents import parse
from urllib.parse import parse_qs


# 请求处理器
class BaseLoger(APIRoute):

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        # 自定义路由的方式内容
        async def custom_route_handler(request: Request) -> Response:
            # 请求前的处理-日志的初始化操作
            ip = request.client.host
            response: Response = await original_route_handler(request)
            # 一个API请求处理完成后的-日志收尾记录
            logger.debug(f"[Api<{ip}>] 访问路由:{request.url.path}-<{request.method}:{response.status_code}>")

            return response

        return custom_route_handler


# 格式化请求处理器
class RecordLoger(BaseLoger):

    need_access_heads_keys = ["content-type", "User-Agent"]

    async def _init_request_data(self, request: Request):
        """初始Request数据"""
        ip, method, url = request.client.host, request.method, request.url.path
        reqeust_id = request.state.request_id
        start_time = request.state.start_time

        try:
            body_form = await request.form()
        except:
            body_form = None

        body = None
        try:
            body_bytes = await request.body()
            if body_bytes:
                try:
                    body = await request.json()
                except:
                    try:
                        body = body_bytes.decode('utf-8')
                    except:
                        body = body_bytes.decode('gb2312')
        except:
            pass

        user_agent = parse(request.headers["user-agent"])

        log_msg = {
            "request_id": reqeust_id,   # 记录请求唯一ID【中间件中生成】
            "OsInfo": {
                "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string),
                'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string),
                "device": {
                    "family": user_agent.device.family,
                    "brand": user_agent.device.brand,
                    "model": user_agent.device.model,
                }
            },      # 浏览器信息
            'url': url,     # 记录请求URL
            'method': method,   # 记录请求方法
            "params": {},
            'ip': ip,   # 记录请求来源IP
            "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}',   # 记录请求的开始时间
            "start_time": f'{start_time}'   # 请求进入中间件的时间
        }
        # 记录请求头信息----如果需要特殊的获取某些请求的记录则做相关的配置即可
        if self.need_access_heads_keys:
            log_msg['headers'] = {i: request.headers.get(i, '') for i in self.need_access_heads_keys}

        # 记录请求提交的参数信息
        if parse_qs(str(request.query_params)):
            log_msg['params']['query_params'] = parse_qs(str(request))
        if body_form:
            log_msg['params']['from'] = body_form
        if body:
            log_msg['params']['body'] = body

        return log_msg

    @staticmethod
    async def _init_response_data(request: Request, response: Response):

        # https://stackoverflow.com/questions/64115628/get-starlette-request-body-in-the-middleware-context
        # 如果响应图的类型，仅仅记录字符串类型的结尾的日志信息
        start_time = request.state.start_time
        request_id = request.state.request_id
        end_time = time.time()
        log_msg = {
            "request_id": request_id,
            "response_content_type": response.headers.get('content-type'),
            "status_code": response.status_code,
            'end_time': end_time,
            'cost_time': f"{end_time - start_time:.3f}",
            'rsp': "",
            "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}'
        }
        if 'image' not in response.media_type and request_id:
            try:
                if isinstance(response, Response):
                    rsp = str(response.body, encoding='utf-8')
                    log_msg["rsp"] = json_helper.json_to_dict(rsp)
            except Exception as e:
                ...
        return log_msg

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        # 自定义路由的方式内容
        async def custom_route_handler(request: Request) -> Response:
            await self._init_request_data(request=request)
            # 请求前的处理-日志的初始化操作
            ip = request.client.host
            response: Response = await original_route_handler(request)
            # 一个API请求处理完成后的-日志收尾记录
            logger.debug(f"[Api<{ip}>] 访问路由:{request.url.path}-<{request.method}:{response.status_code}>")
            await self._init_response_data(request=request, response=response)

            return response

        return custom_route_handler
